//
// Created by 79816 on 2023/1/17.
//

#include "gw.h"
#include <string.h>
#include "common.h"
#include "sha256.h"
#include <stdio.h>
#include "CCL.h"

unsigned char ID[2] = {0, 96};
GW_store gw_store;

REG_request send_id()
{
    gw_store.ID[0] = 0x00;
    gw_store.ID[1] = 0x96;
    REG_request request;
    memcpy(request.ID, ID, 2);
    return request;
}

void store_gw_material(REG_response response)
{
    memcpy(gw_store.k1, response.k1, KEY_LENGTH_BYTES);
    memcpy(gw_store.mr, response.mr, KEY_LENGTH_BYTES);
    gw_store.f = response.f;
    gw_store.n = response.n;
}

// 认证过程第一步
AUTH_request gw_auth_process()
{
    unsigned char hash_result[SHA256_SIZE_BYTES];
    unsigned char k1_result[SHA256_SIZE_BYTES];
    unsigned char i[KEY_LENGTH_BYTES];
    unsigned char j[KEY_LENGTH_BYTES];
    unsigned char f1[KEY_LENGTH_BYTES];

    // gen r2
    srand((unsigned) time(NULL));
    int r2 = rand();
    gw_store.r2 = r2;
   // printf("\ngw_r2:%d\n", r2);

    // calculate i
    sha256(gw_store.k1, sizeof(gw_store.k1), k1_result);
    hash_xor_int(k1_result, r2, i);

    // calculate j
    unsigned char j_plain[KEY_LENGTH_BYTES + 4];
    memcpy(j_plain, gw_store.k1, KEY_LENGTH_BYTES);
    memcpy(j_plain + KEY_LENGTH_BYTES, &r2, 4);
    sha256(j_plain, sizeof(j_plain), hash_result);
    hash_xor_int(hash_result, gw_store.n, j);

    // calculate f1
    unsigned char f1_plain[KEY_LENGTH_BYTES + INT_SIZE * 2 + CHAR_SIZE];
    memcpy(f1_plain, k1_result, KEY_LENGTH_BYTES);
    memcpy(f1_plain + KEY_LENGTH_BYTES, &gw_store.f, CHAR_SIZE);
    memcpy(f1_plain + KEY_LENGTH_BYTES + CHAR_SIZE, &r2, INT_SIZE);
    memcpy(f1_plain + KEY_LENGTH_BYTES + CHAR_SIZE + INT_SIZE, &gw_store.n, INT_SIZE);
    sha256(f1_plain, sizeof(f1_plain), hash_result);
    memcpy(f1, hash_result, KEY_LENGTH_BYTES);

    // add n
    gw_store.n++;

    AUTH_request request;
    memcpy(request.ID, ID, 2);
    memcpy(request.i, i, KEY_LENGTH_BYTES);
    memcpy(request.j, j, KEY_LENGTH_BYTES);
    memcpy(request.mr, gw_store.mr, KEY_LENGTH_BYTES);
    memcpy(request.f1, f1, KEY_LENGTH_BYTES);
    request.f = gw_store.f;

    return request;
}

void gw_update_key(AUTH_response response)
{
    unsigned char k1new[KEY_LENGTH_BYTES];
    unsigned char kseaf[KEY_LENGTH_BYTES];
    unsigned char gw_f2[KEY_LENGTH_BYTES];
    unsigned char xor_temp[KEY_LENGTH_BYTES];
    unsigned char hash_plain[KEY_LENGTH_BYTES + INT_SIZE * 2];
    unsigned char hash_result[SHA256_SIZE_BYTES];

    // calculate k1new
    for (int i = 0; i < KEY_LENGTH_BYTES; ++i)
    {
        xor_temp[i] = response.d1[i] ^ gw_store.k1[i];
    }
    hash_xor_int(xor_temp, gw_store.r2, k1new);

    // calculate kseaf
    int temp_n = gw_store.n + 1;
    memcpy(hash_plain, &gw_store.r2, INT_SIZE);
    memcpy(hash_plain + INT_SIZE, gw_store.k1, KEY_LENGTH_BYTES);
    memcpy(hash_plain + INT_SIZE + KEY_LENGTH_BYTES, &temp_n, INT_SIZE);
    sha256(hash_plain, sizeof(hash_plain), hash_result);
    memcpy(kseaf, hash_result, KEY_LENGTH_BYTES);
    cclWrite("Ks on gw:");
    char print_buf[KEY_LENGTH_BYTES * 2 + 1];
    arrayToStr(kseaf, KEY_LENGTH_BYTES, print_buf);
    print_buf[KEY_LENGTH_BYTES * 2] = '\0';
    cclPrintf("%s", print_buf);

    // calculate gw_f2
    sha256(kseaf, sizeof(kseaf), hash_result);
    memcpy(gw_f2, hash_result, KEY_LENGTH_BYTES);

    // compare gw_f2 with f2
    //print_hex(gw_f2,KEY_LENGTH_BYTES);
    //print_hex(response.f2,KEY_LENGTH_BYTES);
    if (memcmp(gw_f2, response.f2, KEY_LENGTH_BYTES))
    {
        cclPrintf("gateway: authentication failed!");
        exit(-1);
    }
    else
    {
        cclPrintf("gateway: gw_f2 == f2, authentication passed!");
    }
    memcpy(gw_store.k1,k1new,KEY_LENGTH_BYTES);
    gw_store.f=(gw_store.f+1)%2;
}

